Skip to content
This repository has been archived by the owner on Sep 4, 2021. It is now read-only.

Added retry logic to improve state change success #43

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open

Added retry logic to improve state change success #43

wants to merge 3 commits into from

Conversation

caffeinatedMike
Copy link

@caffeinatedMike caffeinatedMike commented Oct 29, 2018

Closes #31

  • Added retry logic to the minimize state_change & state_update timeouts & connection refusals

❗ Important ❗ I need others to test this change to see if it works as intended and to ensure it doesn't pose any unintended side-effects (memory leaks, etc).

@t0ny-peng
Copy link

I'll test it tonight. But the problem I see now is, you always catch the exception with continue. That means the exception might always get ignored.

Will this be better?

        for i in range(3):
            try:
                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
                s.settimeout(self.connection_timeout)
                s.connect((self.address, self.port))
                s.send(payload)
                data = s.recv(1024)
                s.close()
                return data
            except socket.error:
                if i >= 3:
                # raise some exception
                else:
                  continue

@caffeinatedMike
Copy link
Author

Good point, nice catch! I'll make that suggested edit now.

@caffeinatedMike
Copy link
Author

@left4taco Updated to handle like so

except socket.error as e:
    if i == 2:
        raise ConnectionError(e)
    else:
        continue

@t0ny-peng
Copy link

t0ny-peng commented Oct 29, 2018 via email

@t0ny-peng
Copy link

The problem I found with this modification is, getting status too frequently will toggle the switch randomly. This is also mentioned in some ticket but I cannot find it.

@caffeinatedMike
Copy link
Author

Hmm, that's peculiar behavior. I would think with the retry logic it should only fetch upon errors.

Any suggestions? I mainly need this retry logic for actually setting the status since it sometimes fails with the current setup.

@BillSobel
Copy link

BillSobel commented Oct 30, 2018 via email

@caffeinatedMike
Copy link
Author

@BillSobel retry logic moved to set_status function (since that's where it sometimes fails for me).
@left4taco mind testing the new edit?

@t0ny-peng
Copy link

No problem. Will test when I get home.

@t0ny-peng
Copy link

The changes look good to me.

@caffeinatedMike
Copy link
Author

Any word on this? Curious if @BillSobel has had a chance to test this and if he noticed any negative side-effects or if it did in fact improve successful state-change rate.

@BillSobel
Copy link

BillSobel commented Nov 5, 2018 via email

@caffeinatedMike
Copy link
Author

Ahh, my mistake, sorry! In that case, guess I'm looking for @clach04's input then.

@clach04
Copy link
Owner

clach04 commented Nov 13, 2018

Sorry for delay in responding.

Code looks good BUT for re-try logic I'd like to see it parameterized rather than hard coded (in this instance to 3).

Related bug where status calls causes state toggle is upstream issue is #84 (local issue #29) - I've yet to see this but I totally believe this is happening with some devices.

@caffeinatedMike
Copy link
Author

caffeinatedMike commented Nov 13, 2018

@clach04 No worries, I understand life gets busy. I agree that parameterizing the retry logic would be cleaner. How would you propose I do so though? Do you want me to implement an additional (optional) parameter to the def set_status(self, on, switch=1): function? Something along the lines of

def set_status(self, on, switch=1, retries=3):
        """
        Set status of the device to 'on' or 'off'.
        
        Args:
            on(bool):  True for 'on', False for 'off'.
            switch(int): The switch to set
            retries(int): Number of attempts to retry setting status in cause of failure.
        """
        # open device, send request, then close connection
        if isinstance(switch, int):
            switch = str(switch)  # index and payload is a string
        payload = self.generate_payload(SET, {switch:on})
        #print('payload %r' % payload)
        for i in range(retries):
            try:
                data = self._send_receive(payload)
                log.debug('set_status received data=%r', data)
            except Exception:
                if i == retries - 1:
                    raise Exception('set_status failed after exhausting defined consecutive attempts')
                else:
                    continue

        return data

Also, I see that you mention there is an upstream issue related to this. Does that mean we shouldn't be implementing this fix here or is that still ok?

@t0ny-peng
Copy link

I recently found it quite unstable. So I have to move the retry logic into _send_receive and retry for 10 times with a 100ms sleep between each retry.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants